﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VDataAdapter.QueueManagement;
using VDataAdapter.EventManagement;
using PriceLibrary.PriceService;
using System.Threading;
using log4net;

namespace VDataAdapter.PriceServerAdapter
{
    public delegate void PSListenerExceptionHandler(Exception ex);

    abstract class PSEventQueueEnqueuer
    {
        protected IEventStoteredQueue _eventQueue;

        protected PSListenerExceptionHandler _psListenerExceptionHandler;

        public PSEventQueueEnqueuer(IEventStoteredQueue eventQueue, PSListenerExceptionHandler handler)
        {
            _eventQueue = eventQueue;

            _psListenerExceptionHandler = handler;
        }

        public abstract void StartListening();

        public abstract void StopListening();
    }

    interface IPSEventQueueEnqueuerFactory
    {
        PSEventQueueEnqueuer createPSEventHandler(IEventStoteredQueue eventQueue, PSListenerExceptionHandler handler);
    }


    //Create the VDataPSEventQueueEnqueuer
    class VDataPSEventQueueEnqueuerFactory : IPSEventQueueEnqueuerFactory
    {
        protected VDataAdapter.Util.Setting _clientSetting = new VDataAdapter.Util.Setting();

        PSEventQueueEnqueuer IPSEventQueueEnqueuerFactory.createPSEventHandler(IEventStoteredQueue eventQueue, PSListenerExceptionHandler handler)
        {
            return new VDataPSEventQueueEnqueuer(eventQueue,handler, _clientSetting.PriceURI, _clientSetting.ChartURI);
        }
    }

    class VDataPSEventQueueEnqueuer:PSEventQueueEnqueuer, IPriceServerEventHandler
    {
        /// <summary>
        /// Declare logger in standard way according to codeproject log4net tutorial
        /// </summary>
        protected readonly ILog _log = LogManager.GetLogger(typeof(VDataPSEventQueueEnqueuer));

        VDataPSEventAdapter _adapter;
        private string _priceUri;
        private string _chartUri;
            
        public VDataPSEventQueueEnqueuer(IEventStoteredQueue eventQueue,PSListenerExceptionHandler handler, string priceUri, string chartUri)
            : base(eventQueue, handler)
        {
            _adapter = new VDataPSEventAdapter(this);
            _priceUri = priceUri;
            _chartUri = chartUri;
        }

        public override void StartListening()
        {
            _log.Info("Start listening to price server.");
            _adapter.StartListening(_priceUri, _chartUri);
        }

        public override void StopListening()
        {
            _log.Info("Stop listening to price server.");
            _adapter.UnRegisterPriceService();
        }

        public void GetFirstTime(IDictionary<string, StockBase> basePrices, IDictionary<string, StockBase> top3Prices)
        {
            _log.Info("Thread name and id " + Thread.CurrentThread.Name + "#" + Thread.CurrentThread.ManagedThreadId + "#EVENT# Received GetFirstTime event withh basePrices of " + basePrices.Count + " items and top3Prices of " + top3Prices.Count + " items");
            if (basePrices.Count != 0)
            {
                var e = new FirstTimeEvent(basePrices, top3Prices);
                _eventQueue.PutFirstTimeEvent(e);
            }
        }

        /// <summary>
        /// Return a string status indicates floor info about top3Prices
        /// </summary>
        /// <param name="top3Prices"></param>
        /// <returns></returns>
        private string StockSymbols(IDictionary<string, StockBase> top3Prices)
        {
            string result = "";

            foreach (KeyValuePair<string, StockBase> key in top3Prices)
            {
                var stock = (StockInfoDyns)key.Value;
                result += "|" + stock.StockSymbol;
            }

            return result;
        }

        public void Top3PricesStock_Changed(IDictionary<string, StockBase> top3Prices)
        {
            _log.Info(System.Threading.Thread.CurrentThread.Name + "#EVENT# Received Top3PricesStock_Changed with list of " + top3Prices.Count + " stocks : " + StockSymbols(top3Prices));
            var e = new Top3PricesEvent(top3Prices, DateTime.Now);
            _eventQueue.PutTop3PricesEvent(e);
        }


        private string GetMarketInfoIndexesStatus(IDictionary<int, MarketInfo> marketInfos)
        {
            string result = "";
            foreach (KeyValuePair<int, MarketInfo> key in marketInfos)
            {
                result += "|" + key.Key.ToString();
            }
            return result;
        }

        public void MarketInfo_Changed(IDictionary<int, MarketInfo> marketInfos)
        {
            _log.Info(System.Threading.Thread.CurrentThread.Name + "#EVENT# Received MarketInfo_Changed with list of " + marketInfos.Count + " indexes: " + GetMarketInfoIndexesStatus(marketInfos));
            var e = new MarketInfosEvent(marketInfos);
            _eventQueue.PutMarketInfosEvent(e);
        }

        private string GetPutThroughSymbols(IList<StockInfoDyns> newstockbase)
        {
            string result = "";
            foreach (StockInfoDyns stock in newstockbase)
            {
                result += "|" + stock.StockSymbol;
            }
            return result;
        }

        public void PutThroughTopPrices_Changed(IList<StockInfoDyns> newstockbase)
        {
            _log.Info(System.Threading.Thread.CurrentThread.Name + "#EVENT# PutThroughTopPrices_Changed with list of " + newstockbase.Count + " stocks: " + GetPutThroughSymbols(newstockbase));
            var e = new PtTopPricesChangedEvent(newstockbase);
            _eventQueue.PutPtTopPricesEvent(e);
        }

        private string GetPutThroughTransactionsSymbols(IList<Transaction> newstockbase)
        {
            string result = "";
            foreach (Transaction stock in newstockbase)
            {
                result += "|" + stock.Symbol;
            }
            return result;
        }

        public void PutThroughTransactions_Changed(IList<Transaction> newstockbase)
        {
            _log.Info(System.Threading.Thread.CurrentThread.Name + "#EVENT# PutThroughTransactions Event Received with list of " + newstockbase.Count + " transactions: " + GetPutThroughTransactionsSymbols(newstockbase));
            var e = new PtTransactionsChangedEvent(newstockbase);
            _eventQueue.PutPtTransactionsEvent(e);
        }

        private List<int> _countNumber = new List<int>();

        public void Transactions_Changed(IList<PriceLibrary.ChartService.Transaction> transactions, int countNumber, int totalCountNumber)
        {
            _log.Info(System.Threading.Thread.CurrentThread.Name + "Transactions_Changed Received with list of " + transactions.Count + " transactions" + " in " + countNumber.ToString() + " / " + totalCountNumber.ToString());
            if(_countNumber.Contains(countNumber))
            {
                return;
            }

            _countNumber.Add(countNumber);
            var e = new TransactionsEvent(transactions, countNumber, totalCountNumber, DateTime.Now);
            _eventQueue.PutTransactionsEvent(e);
        }

        /// <summary>
        /// Do what to do here
        /// </summary>
        /// <param name="ex"></param>
        public void ConnectionErrorHandler(Exception ex)
        {
            _psListenerExceptionHandler(ex);
        }
    }
}
